//------------------------------------------------------------------------------ 
// <copyright file="ExclusiveTcpListener.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//----------------------------------------------------------------------------- 

using System; 
using System.Net; 
using System.Net.Sockets;
 
namespace System.Runtime.Remoting.Channels
{

    // This class provides a TcpListener that is capable of setting the ExclusiveAddressUse flag 
    // on a socket, which will prevent another app from hijacking our port. This flag is not supported
    // on Win9x, so we just omit the call to SetSocketOption on non-NT platforms. 
    internal class ExclusiveTcpListener : TcpListener 
    {
        internal ExclusiveTcpListener(IPAddress localaddr, int port) : base(localaddr, port) {} 

        // Start will attempt to start listening.  If exclusiveAddressUse is true, then
        // we will attempt to use the ExclusiveAddressUse flag, but if bind fails (which will
        // happen for a regular user on win2k and xp), we try again without the flag. 
        internal void Start(bool exclusiveAddressUse)
        { 
            // we only attempt to set the socket option if 
            //   1. the exclusiveAddressUse param is true
            //   2. the platform is NT - this option is unavailable on other platforms 
            //   3. Server is not null - if it IS null, base.Start will throw a nice error for us
            //   4. the listener is not already listening - it's too late in that case (base.Start will return immediately)
            bool attemptSetSocketOption = exclusiveAddressUse &&
#if !FEATURE_PAL 
                                          Environment.OSVersion.Platform == PlatformID.Win32NT &&
#endif // !FEATURE_PAL 
                                          base.Server != null && 
                                          !base.Active;
 
            if (attemptSetSocketOption)
            {
                // Attempt to set the option.  We won't actually find out if this fails until
                // we try to bind (which happens in base.Start()). 
                base.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, 1);
            } 
 
            try
            { 
                base.Start();
            }
            catch (SocketException)
            { 
                if (attemptSetSocketOption)
                { 
                    // Turn off the option and try again - maybe this process doesn't have 
                    // permission to use the option.
                    Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, 0); 
                    base.Start();
                }
                else
                { 
                    // It wasn't because we set the ExclusiveAddressUse option - let the
                    // exception bubble up 
                    throw; 
                }
            } 
        }

        internal bool IsListening { get { return Active; } }
 
    }
 
} // namespace System.Runtime.Remoting.Channels 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// <copyright file="ExclusiveTcpListener.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//----------------------------------------------------------------------------- 

using System; 
using System.Net; 
using System.Net.Sockets;
 
namespace System.Runtime.Remoting.Channels
{

    // This class provides a TcpListener that is capable of setting the ExclusiveAddressUse flag 
    // on a socket, which will prevent another app from hijacking our port. This flag is not supported
    // on Win9x, so we just omit the call to SetSocketOption on non-NT platforms. 
    internal class ExclusiveTcpListener : TcpListener 
    {
        internal ExclusiveTcpListener(IPAddress localaddr, int port) : base(localaddr, port) {} 

        // Start will attempt to start listening.  If exclusiveAddressUse is true, then
        // we will attempt to use the ExclusiveAddressUse flag, but if bind fails (which will
        // happen for a regular user on win2k and xp), we try again without the flag. 
        internal void Start(bool exclusiveAddressUse)
        { 
            // we only attempt to set the socket option if 
            //   1. the exclusiveAddressUse param is true
            //   2. the platform is NT - this option is unavailable on other platforms 
            //   3. Server is not null - if it IS null, base.Start will throw a nice error for us
            //   4. the listener is not already listening - it's too late in that case (base.Start will return immediately)
            bool attemptSetSocketOption = exclusiveAddressUse &&
#if !FEATURE_PAL 
                                          Environment.OSVersion.Platform == PlatformID.Win32NT &&
#endif // !FEATURE_PAL 
                                          base.Server != null && 
                                          !base.Active;
 
            if (attemptSetSocketOption)
            {
                // Attempt to set the option.  We won't actually find out if this fails until
                // we try to bind (which happens in base.Start()). 
                base.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, 1);
            } 
 
            try
            { 
                base.Start();
            }
            catch (SocketException)
            { 
                if (attemptSetSocketOption)
                { 
                    // Turn off the option and try again - maybe this process doesn't have 
                    // permission to use the option.
                    Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, 0); 
                    base.Start();
                }
                else
                { 
                    // It wasn't because we set the ExclusiveAddressUse option - let the
                    // exception bubble up 
                    throw; 
                }
            } 
        }

        internal bool IsListening { get { return Active; } }
 
    }
 
} // namespace System.Runtime.Remoting.Channels 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
